\documentclass{article}

\usepackage{ctex}
\usepackage{graphicx}
\usepackage{float}
\usepackage{datetime}
\usepackage{listings}

\usepackage{xcolor}

\usepackage{xcolor}
\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{mymauve}{rgb}{0.58,0,0.82}
\lstset{ %
	backgroundcolor=\color{white},      % choose the background color
	basicstyle=\footnotesize\yahei,  % size of fonts used for the code
	columns=fullflexible,
	tabsize=4,
	breaklines=true,               % automatic line breaking only at whitespace
	captionpos=b,                  % sets the caption-position to bottom
	commentstyle=\color{mygreen},  % comment style
	escapeinside={\%*}{*)},        % if you want to add LaTeX within your code
	keywordstyle=\color{blue},     % keyword style
	stringstyle=\color{mymauve}\yahei,  % string literal style
	frame=single,
	rulesepcolor=\color{red!20!green!20!blue!20},
	% identifierstyle=\color{red},
	language=c++,
    numbers=left,
    escapeinside=``,
}



\title{Calculator Report}
\author{叶睿浩		3190104031}
\date{\today}


\begin{document}
\maketitle
这是Calculator作业的report。

\section{设计思路介绍}
本次作业利用栈与队列的数据结构，实现五则运算器的各项功能。

计算器主要通过两个函数来完成计算。第一个函数主要完成中缀转后缀的功能，而第二个函数则是完成后缀表达式的计算问题。

\subsection{中缀转后缀函数介绍}
这个函数完成的是中缀转后缀的功能，该函数的输入为一个字符数组指针，输出为一个字符类型的队列。主要可分为以下几个步骤：

1、预处理——去掉字符数组内全部的空格和制表符；

2、读取首个字符，判断正确性——若为除“-”外的操作符，则直接报错；

3、依次读取各个字符，将整个中缀表达式转为后缀表达式，并以队列的形式输出。

这里面和课本当中最大的不同在于为了能够进行浮点数的运算，我规定输出的队列当中所有的数字的前后都会空有一个空格。同时在读取数字时，
会建立一个临时的字符串变量用来存放当前读取的数字。显然对于这样一个数字串需要对其首个数字和最后一个数字进行额外处理。这里对于数字
串的首个数字将利用numStart变量进行标识，若读取到数字时，numStart显示数字串未开始，则执行一段数字串初始化的代码；但若此时后一个
字符已经不再是数字且也不是小数点时，就认为这个数字串已经结束，这个时候就需要执行标识数字串最后一个数字的代码（这种情况也就是在数字
串中只有一个数字是才会发生）。若当前数字字符的后一位不再是数字并且该字符也不是小数点"."，则认为这个数字串已经结束，将这个字符串变
量的内容放入到队列当中。

关于数字字符的读取，具体代码如下：

为了实现浮点数的计算，需要对“.”进行额外处理。显然，“.”是数字串的一部分，因此对其的操作应当将其视为数字串的一部分；但同时注意到
读取到“.”时，数字串必须已经开始了，而且一个数字串内不可出现两个“.”，这些错误情况需要额外进行处理。


为了实现负数的计算，需要对“-”的情况进行额外处理。究其根本，主要是因为“-”承担了操作符和数字正负号标识两个功能。这里我引入了这样
的一个判断：读取到“-”时，若“-”前面为左括号“(”且“-”后面为数字时，那么就认为它此时起到负号标识符的作用，这个时候的负号将会被当做
数字串的一部分进行处理；除此以外都认为“-”为一个操作符。同时还需要额外处理一个情况，也就是当负号为首个字符时的情况，那种情况会在
读取首个字符时进行额外处理。

剩下的有关操作符和括号的操作与课上老师的做法几乎没有差别，只是增加了一些报错处理。

总的报错函数有10个。除去前面已经展示过的，还有的就是有关括号的报错函数。有关括号的报错，我主要考虑了这样一些情况：

1、括号数不匹配——左括号和右括号数量不匹配导致报错

2、左括号后面的第一个字符不能为操作符

\subsection{后缀表达式计算函数介绍}

后缀表达式计算函数的输入为队列，输出为double类型。其整体逻辑较为简单，框架也是和书上的差不多，但在有些部分上进行了微调——即数字读
取以及负号读取上。

在数字读取过程中，会将当前读取到的数字字符存入临时字符串变量num当中。由于数字前后有空格，因此只要当前读取到的字符为空格时，就可以
知道当前的数字串已经结束，然后便将num的数据全部压入到一个临时的栈中。

当读取到操作符时，会从栈中弹出两个数字，用来计算。其计算顺序按照弹出先后若分别命名为num1（最先弹出的）、num2（最后弹出的），那么
计算结果总是可以表示为num=num2#num1 （“#”表示读取到的操作符）。然后再将num的值重新压入到栈中。

在这个过程中，对于负号的读取需要进行额外的关照。如果负号后面紧跟着数字的话，那么此时的“-”为数字串的一部分，应当将其保存到num当中；
若不是，那么此时的“-”是作为一个操作符进行处理。

最后函数的返回结果为栈中最后剩余的数字。

\section{不同样例的测试结果}

首先是作业要求中的样例，其测试结果如下：
\begin{lstlisting}
    input1:2^(1 + 3) - 5*(15.23)/(1 + 2)*3 -5 
    output1:2^(1+3)-5*(15.23)/(1+2)*3-5 = -65.1499
    input2:1.25 + ( 3  * (1 + 2^2)*3 - 43)^(4-2)
    output2:1.25+(3*(1+2^2)*3-43)^(4-2) = 5.25
    input3:2^(1 + 3)) - 5*(15.23)/(1 + 2)*3 -5 
    output3:错误：括号不匹配
    input4:2^(1 + 3) - 5*(15.23)/(1 - 1)*3 -5 
    output4:错误：除数为0
\end{lstlisting}
符合作业要求。

另外我的计算器还可以计算负数输入，这一点在作业要求的测试样例中没有体现：
\begin{lstlisting}
    input:2^(-1 + 3) - 5*(15.23)/(1 + 2)*3 -5 
    output:2^(-1+3)-5*(15.23)/(1+2)*3-5 = -77.1499
\end{lstlisting}

同时针对我专门设计的报错函数，也进行一些样例测试：

\begin{lstlisting}
    input5:2^(1 + 3) - 5*(15.23)/(1 - 1)*3 -5 %
    output5:错误：非法字符
    input6:+2^(1 + 3) - 5*(15.23)/(1 - 1)*3 -5 
    output6:错误：第一个有效字符不能为操作符
    input7:2^(+1 + 3) - 5*(15.23)/(1 - 1)*3 -5 
    output7:错误：括号内第一个有效字符不能为操作符
    input8:2^(1 + 3) - 5*(15.23)/(1 - 1)*3 -5- 
    output8:错误：操作符后面不能为空
    input9:2^(1 + 3) - 5*(15.23-)/(1 - 1)*3 -5 
    output9:错误：操作符后面只能接左括号或者数字
    input10:2^(1 + 3) - 5*(15.)/(1 - 1)*3 -5 
    output10:错误：小数点后面不能为非数字字符
    input11:2^(1 + 3) - 5*(1.5.23)/(1 - 1)*3 -5 
    output11:错误：小数点在数字串中重复出现
    input12:2^(1 + 3) - 5*(.23)/(1 - 1)*3 -5 
    output12:错误：小数点前面没有数字
\end{lstlisting}










\end{document}